-
-
Notifications
You must be signed in to change notification settings - Fork 754
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use correct WebSocket error codes #1753
Conversation
3e01fcd
to
71b0541
Compare
1012 means server restarted and indicates client that it can retry connection right? What if the server is gone away completely? Shouldn't it be 1001?🤔 |
1a1a0b8
to
91b0633
Compare
04277bd
to
cec0a7d
Compare
cec0a7d
to
3f91b00
Compare
@@ -553,22 +553,22 @@ async def app(scope, receive, send): | |||
@pytest.mark.anyio | |||
@pytest.mark.parametrize("ws_protocol_cls", WS_PROTOCOLS) | |||
@pytest.mark.parametrize("http_protocol_cls", HTTP_PROTOCOLS) | |||
async def test_not_accept_on_connection_lost(ws_protocol_cls, http_protocol_cls): | |||
async def test_connection_lost_before_handshake_complete( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A more meaningful name on what scenario we are testing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A more meaningful name on what scenario we are testing.
ETS TRADEX SERVICES LLP
BeNADABURAMbVADAKARA
NADAPURAM , VADAKARA, Kerala Waterm98562820968
Server:4
10:10AM
366/1
02-21-2023
1/10379
SALE
210000083
403226
CardXXXXXXXXXXXXXXXXmber
CardPresent to Remove Card EntrySwipe/Chomark
APPROVAL:3BC02
1 for 192.168.89.191Rs 210000083.00
GSTs 16926006.69
GSRs 12705005.02
AMRs 239631094.71Mem to Remove Watermark
†TIP
=TOTAL
TIP SUGGESTION:
Tip 15%
Tip 18%
Tip20%
R$31500012.45 Rs37800014.94 Rs4200C
@@ -577,6 +577,8 @@ async def websocket_session(uri): | |||
task.cancel() | |||
send_accept_task.set() | |||
|
|||
assert disconnect_message == {"type": "websocket.disconnect", "code": 1006} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The connection was closed without a close frame, so we send a 1006
.
|
||
assert frames == [b"abc", b"abc", b"abc"] | ||
assert disconnect_message == {"type": "websocket.disconnect", "code": 1000} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The client closed the connection with a close frame, and the code interpreted by the WebSocket
packages is 1000
i.e. normal closure.
async with websockets.client.connect(uri): | ||
while True: | ||
await asyncio.sleep(0.1) | ||
await websockets.client.connect(uri) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was changed because connect
hangs until we are able to connect with the server. There was a previous misconception that we'd actually hit the while True
logic.
We are never able to complete the handshake, as we don't send the websocket.accept
, so we cancel the task below and let the application continue.
self.lost_connection_before_handshake = ( | ||
not self.handshake_completed_event.is_set() | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to know if the connection was lost before the handshake was completed to determine what code we'll be sending to the application.
- If we lost connection before the handshake is completed, then we should send a
1006
. - If we lost connection after the handshake is completed, then we should send a
1005
.
@@ -335,11 +339,13 @@ async def asgi_receive( | |||
|
|||
await self.handshake_completed_event.wait() | |||
|
|||
if self.closed_event.is_set(): | |||
# If client disconnected, use WebSocketServerProtocol.close_code property. | |||
if self.lost_connection_before_handshake: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of lost_connection_before_handshake
, I can create an attribute called lost_connection
, and do the conditional before the await self.handshake_completed_event.wait()
above. What do you prefer? 🤔
(I think this alternative will work, I'm not sure if I'm missing something...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Meaning we wouldn’t hit await self.handshake_completed_event.wait()
at all in connection is lost?
If that’s the case, it seems better 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I said doesn't work.
Conceptually, if we think about a web server, I think it doesn't make sense to send a code that says that the server has stopped for good. We think about it as a long-living software. In other words, when we call "shutdown", it's because it's going to be up again. If the application wants, it can send a |
Thanks! This justifies! |
Maybe this is not trivial, but I really want to include this in the release. Mainly because this is the "WebSockets release". 👀 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good!😄
It'd be great if someone can confirm the comment on lost_connection_before_handshake
change where Kludex asked about an alternative approach 😊
self.connections.remove(self) | ||
|
||
if self.logger.level <= TRACE_LOG_LEVEL: | ||
prefix = "%s:%d - " % tuple(self.client) if self.client else "" | ||
self.logger.log(TRACE_LOG_LEVEL, "%sWebSocket connection lost", prefix) | ||
|
||
self.handshake_complete = True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is matching the behavior with the websockets
implementation.
This is a very confusing subject.
There are 4 ways for us to send
websocket.disconnect
to the application:1012
(Service Restart)wsproto
sendsevent.code
, andwebsockets
sendsexc.code
1006
(Abnormal Closure)1005
(No Status Rcvd)Note: If the connection was lost before the handshake was completed, then it should be a
1006
.This PR aims to match the behavior on both websockets implementations, and fixes https://github.com/encode/uvicorn/pull/1737/files#r1009855193.